package com.cencat.user.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 缓存配置类
 * 配置Redis缓存管理器和缓存策略
 * 
 * @author cencat
 * @since 2024-01-01
 */
@Configuration
@EnableCaching
public class CacheConfig {

    /**
     * 缓存管理器配置
     * 
     * @param redisConnectionFactory Redis连接工厂
     * @return 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 默认缓存配置
        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30)) // 默认30分钟过期
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .disableCachingNullValues(); // 不缓存null值

        // 针对不同缓存的个性化配置
        Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
        
        // 用户分页查询缓存 - 5分钟过期
        cacheConfigurations.put("userPage", defaultConfig.entryTtl(Duration.ofMinutes(5)));
        
        // 角色分页查询缓存 - 10分钟过期
        cacheConfigurations.put("rolePage", defaultConfig.entryTtl(Duration.ofMinutes(10)));
        
        // 权限分页查询缓存 - 15分钟过期
        cacheConfigurations.put("permissionPage", defaultConfig.entryTtl(Duration.ofMinutes(15)));
        
        // 用户角色关联分页查询缓存 - 5分钟过期
        cacheConfigurations.put("userRolePage", defaultConfig.entryTtl(Duration.ofMinutes(5)));
        
        // 角色权限关联分页查询缓存 - 10分钟过期
        cacheConfigurations.put("rolePermissionPage", defaultConfig.entryTtl(Duration.ofMinutes(10)));
        
        // 用户详情缓存 - 1小时过期
        cacheConfigurations.put("userDetail", defaultConfig.entryTtl(Duration.ofHours(1)));
        
        // 角色详情缓存 - 2小时过期
        cacheConfigurations.put("roleDetail", defaultConfig.entryTtl(Duration.ofHours(2)));
        
        // 权限详情缓存 - 4小时过期
        cacheConfigurations.put("permissionDetail", defaultConfig.entryTtl(Duration.ofHours(4)));

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(defaultConfig)
                .withInitialCacheConfigurations(cacheConfigurations)
                .build();
    }

    /**
     * 缓存键生成器
     * 用于生成统一格式的缓存键
     */
    public static class CacheKeyGenerator {
        
        /**
         * 生成用户分页查询缓存键
         * 
         * @param tenantId 租户ID
         * @param pageNum 页码
         * @param pageSize 页大小
         * @param username 用户名（可选）
         * @param status 状态（可选）
         * @return 缓存键
         */
        public static String generateUserPageKey(Long tenantId, Long pageNum, Long pageSize, 
                                                String username, String status) {
            StringBuilder keyBuilder = new StringBuilder()
                    .append("tenant:").append(tenantId)
                    .append(":page:").append(pageNum)
                    .append(":size:").append(pageSize);
            
            if (username != null && !username.trim().isEmpty()) {
                keyBuilder.append(":username:").append(username);
            }
            
            if (status != null && !status.trim().isEmpty()) {
                keyBuilder.append(":status:").append(status);
            }
            
            return keyBuilder.toString();
        }
        
        /**
         * 生成角色分页查询缓存键
         * 
         * @param tenantId 租户ID
         * @param pageNum 页码
         * @param pageSize 页大小
         * @param roleName 角色名（可选）
         * @param status 状态（可选）
         * @return 缓存键
         */
        public static String generateRolePageKey(Long tenantId, Long pageNum, Long pageSize, 
                                                String roleName, String status) {
            StringBuilder keyBuilder = new StringBuilder()
                    .append("tenant:").append(tenantId)
                    .append(":page:").append(pageNum)
                    .append(":size:").append(pageSize);
            
            if (roleName != null && !roleName.trim().isEmpty()) {
                keyBuilder.append(":roleName:").append(roleName);
            }
            
            if (status != null && !status.trim().isEmpty()) {
                keyBuilder.append(":status:").append(status);
            }
            
            return keyBuilder.toString();
        }
        
        /**
         * 生成权限分页查询缓存键
         * 
         * @param tenantId 租户ID
         * @param pageNum 页码
         * @param pageSize 页大小
         * @param permissionName 权限名（可选）
         * @param status 状态（可选）
         * @return 缓存键
         */
        public static String generatePermissionPageKey(Long tenantId, Long pageNum, Long pageSize, 
                                                      String permissionName, String status) {
            StringBuilder keyBuilder = new StringBuilder()
                    .append("tenant:").append(tenantId)
                    .append(":page:").append(pageNum)
                    .append(":size:").append(pageSize);
            
            if (permissionName != null && !permissionName.trim().isEmpty()) {
                keyBuilder.append(":permissionName:").append(permissionName);
            }
            
            if (status != null && !status.trim().isEmpty()) {
                keyBuilder.append(":status:").append(status);
            }
            
            return keyBuilder.toString();
        }
    }
}